home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / JMenuBar.java < prev    next >
Text File  |  1998-06-30  |  19KB  |  657 lines

  1. /*
  2.  * @(#)JMenuBar.java    1.52 98/04/09
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing;
  22.  
  23. import java.awt.Component;
  24. import java.awt.Dimension;
  25. import java.awt.Graphics;
  26. import java.awt.Insets;
  27. import java.awt.LayoutManager;
  28. import java.awt.Point;
  29. import java.awt.Rectangle;
  30. import java.awt.event.*;
  31. import java.util.Vector;
  32. import java.util.Enumeration;
  33.  
  34. import java.io.Serializable;
  35. import java.io.ObjectOutputStream;
  36. import java.io.ObjectInputStream;
  37. import java.io.IOException;
  38.  
  39. import com.sun.java.swing.event.*;
  40. import com.sun.java.swing.border.Border;
  41. import com.sun.java.swing.plaf.*;
  42. import com.sun.java.accessibility.*;
  43.  
  44. /**
  45.  * An implementation of a MenuBar. You add JMenu objects to the
  46.  * menu bar to construct a menu. When the user selects a JMenu
  47.  * object, its associated JPopupMenu is displayed, allowing the
  48.  * user to select one of the JMenuItems on it.
  49.  * <p>
  50.  * For the keyboard keys used by this component in the standard Look and
  51.  * Feel (L&F) renditions, see the
  52.  * <a href="doc-files/Key-Index.html#JMenuBar">JMenuBar</a> key assignments.
  53.  * <p>
  54.  * Warning: serialized objects of this class will not be compatible with
  55.  * future swing releases.  The current serialization support is appropriate 
  56.  * for short term storage or RMI between Swing1.0 applications.  It will
  57.  * not be possible to load serialized Swing1.0 objects with future releases
  58.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  59.  * baseline for the serialized form of Swing objects.
  60.  *
  61.  * @version 1.52 04/09/98
  62.  * @author Georges Saab
  63.  * @author David Karlton
  64.  * @author Arnaud Weber
  65.  * @see JMenu
  66.  * @see JPopupMenu
  67.  * @see JMenuItem
  68.  */
  69. public class JMenuBar extends JComponent implements Accessible,MenuElement
  70. {    
  71.     /*
  72.      * Model for the selected subcontrol
  73.      */
  74.     private transient SingleSelectionModel selectionModel;
  75.  
  76.     private boolean paintBorder           = true;
  77.     private Insets     margin             = null;
  78.  
  79.     /**
  80.      * Creates a new menu bar.
  81.      */
  82.     public JMenuBar() {
  83.         super();
  84.         setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
  85.         setSelectionModel(new DefaultSingleSelectionModel());
  86.         updateUI();
  87.     }
  88.  
  89.     /**
  90.      * Returns the menubar's current UI.
  91.      * @see setUI
  92.      */
  93.     public MenuBarUI getUI() {
  94.         return (MenuBarUI)ui;
  95.     }
  96.     
  97.     /**
  98.      * Sets the L&F object that renders this component.
  99.      *
  100.      * @param ui the new MenuBarUI L&F object
  101.      * @see UIDefaults#getUI
  102.      */
  103.     public void setUI(MenuBarUI ui) {
  104.         super.setUI(ui);
  105.     }
  106.     
  107.     /**
  108.      * Notification from the UIFactory that the L&F has changed. 
  109.      * Called to replace the UI with the latest version from the 
  110.      * UIFactory.
  111.      *
  112.      * @see JComponent#updateUI
  113.      */
  114.     public void updateUI() {
  115.         setUI((MenuBarUI)UIManager.getUI(this));
  116.     }
  117.  
  118.  
  119.     /**
  120.      * Returns the name of the L&F class that renders this component.
  121.      *
  122.      * @return "MenuBarUI"
  123.      * @see JComponent#getUIClassID
  124.      * @see UIDefaults#getUI
  125.      */
  126.     public String getUIClassID() {
  127.         return "MenuBarUI";
  128.     }
  129.  
  130.  
  131.     /**
  132.      * Returns the model object that handles single selections.
  133.      *
  134.      * @return the SingleSelectionModel in use
  135.      * @see SingleSelectionModel
  136.      */
  137.     public SingleSelectionModel getSelectionModel() {
  138.         return selectionModel;
  139.     }
  140.  
  141.     /**
  142.      * Set the model object to handle single selections.
  143.      *
  144.      * @param model the SingleSelectionModel to use
  145.      * @see SingleSelectionModel
  146.      */
  147.     public void setSelectionModel(SingleSelectionModel model) {
  148.         final JMenuBar thisMenuBar = this;
  149.         selectionModel = model;
  150.     }
  151.  
  152.  
  153.     /**
  154.      * Appends the specified menu to the end of the menu bar.
  155.      *
  156.      * @param c the JMenu component to add
  157.      */
  158.     public JMenu add(JMenu c) {
  159.         Dimension size = c.getSize();
  160.         size.height = Short.MAX_VALUE;
  161.         // c.setMaximumSize(size);
  162.         super.add(c);
  163.         getUI().registerMenu(c);
  164.         return c;
  165.     }
  166.  
  167.     /**
  168.      * Gets the menu at the specified position in the menu bar.
  169.      *
  170.      * @param index  an int giving the position in the menu bar, where
  171.      *               0 is the first position
  172.      * @return the JMenu at that position
  173.      */
  174.     public JMenu getMenu(int index) {
  175.         Component c = getComponentAtIndex(index);
  176.         if (c instanceof JMenu) 
  177.             return (JMenu) c;
  178.         return null;
  179.     }
  180.  
  181.     /**
  182.      * Returns the number of items in the menu bar.
  183.      *
  184.      * @return the number of items in the menu bar
  185.      */
  186.     public int getMenuCount() {
  187.         return getComponentCount();
  188.     }
  189.  
  190.     /**
  191.      * Removes the component at the specified index.
  192.      *
  193.      * @param index  an int specifying the menu bar position, where 0 = first
  194.      */
  195.     public void remove(int index) {
  196.         Component c = getComponent(index);
  197.         if(c instanceof JMenu)
  198.             getUI().unregisterMenu((JMenu)c);
  199.         super.remove(index);
  200.     }
  201.  
  202.     /**
  203.      * Sets the help menu that appears when the user selects the
  204.      * "help" option in the menu bar.
  205.      *
  206.      * @param menu the JMenu that delivers help to the user
  207.      */
  208.     public void setHelpMenu(JMenu menu) {
  209.         throw new Error("setHelpMenu() not yet implemented.");
  210.     }
  211.  
  212.     /**
  213.      * Gets the help menu for the menu bar.
  214.      *
  215.      * @return the JMenu that delivers help to the user
  216.      */
  217.     public JMenu getHelpMenu() {
  218.         throw new Error("getHelpMenu() not yet implemented.");
  219.     }
  220.  
  221.     /**
  222.      * Returns the component at the specified index.
  223.      *
  224.      * @param i an int specifying the position, where 0 = first
  225.      * @return the Component at the position, or null for an
  226.      *         invalid index
  227.      */
  228.     public Component getComponentAtIndex(int i) {
  229.         int ncomponents = this.getComponentCount();
  230.         if (i <= ncomponents) {
  231.             Component[] component = this.getComponents();
  232.             return component[i];
  233.         }
  234.         return null;
  235.     }
  236.  
  237.     /**
  238.      * Returns the index of the specified component.
  239.      *
  240.      * @param c  the Component to find
  241.      * @return an int giving the component's position, where 0 = first
  242.      */
  243.     public int getComponentIndex(Component c) {
  244.         int ncomponents = this.getComponentCount();
  245.         Component[] component = this.getComponents();
  246.         for (int i = 0 ; i < ncomponents ; i++) {
  247.             Component comp = component[i];
  248.             if (comp == c) 
  249.                 return i;
  250.         }
  251.         return -1;
  252.     }
  253.  
  254.     /**
  255.      * Sets the currently selected component, producing a
  256.      * a change to the selection model.
  257.      *
  258.      * @param sel the Component to select
  259.      */
  260.     public void setSelected(Component sel) {    
  261.         SingleSelectionModel model = getSelectionModel();
  262.         int index = getComponentIndex(sel);
  263.         model.setSelectedIndex(index);
  264.     }
  265.  
  266.     /**
  267.      * Returns true if the MenuBar currently has a component selected
  268.      *
  269.      * @return true if a selection has been made, else false
  270.      */
  271.     public boolean isSelected() {       
  272.         return selectionModel.isSelected();
  273.     }
  274.  
  275.     /** 
  276.      * Returns true if a the Menubar's border should be painted.
  277.      *
  278.      * @return  true if the border should be painted, else false
  279.      */
  280.     public boolean isBorderPainted() {
  281.         return paintBorder;
  282.     }
  283.  
  284.     /** 
  285.      * Determines whether the MenuBar's current border will be painted.
  286.      *
  287.      * @param s  true if the border should be painted, else false
  288.      */
  289.     public void setBorderPainted(boolean s) {
  290.         paintBorder = s;
  291.     }
  292.  
  293.     /**
  294.      * Paint the menubar's border if BorderPainted property is true.
  295.      * 
  296.      * @param g the Graphics context to use for painting
  297.      * @see JComponent#paint
  298.      * @see JComponent#setBorder
  299.      */
  300.     protected void paintBorder(Graphics g) {    
  301.         if (isBorderPainted()) {
  302.             super.paintBorder(g);
  303.         }
  304.     }
  305.  
  306.     /**
  307.      * Sets the margin between the menubar's border and
  308.      * its menus. Setting to null will cause the menubar to
  309.      * use the default margins.
  310.      *
  311.      * @param margin an Insets object containing the margin values
  312.      * @see Insets
  313.      */
  314.     public void setMargin(Insets margin) {
  315.         this.margin = margin;
  316.         invalidate();
  317.     }
  318.  
  319.     /**
  320.      * Returns the margin between the menubar's border and
  321.      * its menus.
  322.      * 
  323.      * @return an Insets object containing the margin values
  324.      * @see Insets
  325.      */
  326.     public Insets getMargin() {
  327.         if(margin == null) {
  328.             return new Insets(0,0,0,0);
  329.         } else {
  330.             return margin;
  331.         }
  332.     }
  333.  
  334.  
  335.     /**
  336.      * Implemented to be a MenuElement -- does nothing. 
  337.      *
  338.      * @see #getSubElements
  339.      */
  340.     public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {
  341.     }
  342.  
  343.     /**
  344.      * Implemented to be a MenuElement -- does nothing.
  345.      *
  346.      * @see #getSubElements
  347.      */
  348.     public void processKeyEvent(KeyEvent e,MenuElement path[],MenuSelectionManager manager) {
  349.     }
  350.  
  351.     /** 
  352.      * Implemented to be a MenuElement -- does nothing.
  353.      *
  354.      * @see #getSubElements
  355.      */
  356.     public void menuSelectionChanged(boolean isIncluded) {
  357.     }
  358.     
  359.     /** 
  360.      * Implemented to be a MenuElement -- returns the menus in this menu 
  361.      * bar. This is the reason for implementing the MenuElement
  362.      * interface -- so that the menu bar can be treated the same as
  363.      * other menu elements.
  364.      */
  365.     public MenuElement[] getSubElements() {
  366.         int menuCount = getMenuCount();
  367.         int i;
  368.         MenuElement result[] = new MenuElement[menuCount];
  369.         for(i=0;i<menuCount;i++)
  370.             result[i] = getMenu(i);
  371.         return result;
  372.     }
  373.     
  374.     /** 
  375.      * Implemented to be a MenuElement. Returns this object. 
  376.      *
  377.      * @return the current Component (this)
  378.      * @see #getSubElements
  379.      */
  380.     public Component getComponent() {
  381.         return this;
  382.     }
  383. /////////////////
  384. // Accessibility support
  385. ////////////////
  386.  
  387.     /**
  388.      * Get the AccessibleContext associated with this JComponent
  389.      *
  390.      * @return the AccessibleContext of this JComponent
  391.      */
  392.     public AccessibleContext getAccessibleContext() {
  393.         if (accessibleContext == null) {
  394.             accessibleContext = new AccessibleJMenuBar();
  395.         }
  396.         return accessibleContext;
  397.     }
  398.  
  399.     /**
  400.      * The class used to obtain the accessible role for this object.
  401.      * <p>
  402.      * Warning: serialized objects of this class will not be compatible with
  403.      * future swing releases.  The current serialization support is appropriate
  404.      * for short term storage or RMI between Swing1.0 applications.  It will
  405.      * not be possible to load serialized Swing1.0 objects with future releases
  406.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  407.      * baseline for the serialized form of Swing objects.
  408.      */
  409.     protected class AccessibleJMenuBar extends AccessibleJComponent 
  410.         implements AccessibleSelection {
  411.  
  412.         /**
  413.          * Get the accessible state set of this object.
  414.          *
  415.          * @return an instance of AccessibleState containing the current state 
  416.          *         of the object
  417.          */
  418.         public AccessibleStateSet getAccessibleStateSet() {
  419.             AccessibleStateSet states = super.getAccessibleStateSet();
  420.             return states;
  421.         }
  422.  
  423.         /**
  424.          * Get the role of this object.
  425.          *
  426.          * @return an instance of AccessibleRole describing the role of the 
  427.          * object
  428.          */
  429.         public AccessibleRole getAccessibleRole() {
  430.             return AccessibleRole.MENU_BAR;
  431.         }
  432.  
  433.         /**
  434.          * Get the AccessibleSelection associated with this object if one
  435.          * exists.  Otherwise return null.
  436.          */
  437.         public AccessibleSelection getAccessibleSelection() {
  438.             return this;
  439.         }
  440.  
  441.         /**
  442.          * Returns 1 if a menu is currently selected in this menu bar.
  443.          *
  444.          * @return 1 if a menu is currently selected, else 0
  445.          */
  446.          public int getAccessibleSelectionCount() {
  447.             if (isSelected()) {
  448.                 return 1;
  449.             } else {
  450.                 return 0;
  451.             }
  452.          }
  453.     
  454.         /**
  455.          * Returns the currently selected menu if one is selected, 
  456.          * otherwise null.
  457.          */
  458.          public Accessible getAccessibleSelection(int i) {
  459.             if (isSelected()) {
  460.         if (i != 0) {    // single selection model for JMenuBar
  461.             return null;
  462.         }
  463.                 int j = getSelectionModel().getSelectedIndex();
  464.                 if (getComponentAtIndex(j) instanceof Accessible) {
  465.                     return (Accessible) getComponentAtIndex(j);
  466.                 }           
  467.             }
  468.             return null;
  469.          }
  470.  
  471.         /**
  472.          * Returns true if the current child of this object is selected.
  473.          *
  474.          * @param i the zero-based index of the child in this Accessible 
  475.          * object.
  476.          * @see AccessibleContext#getAccessibleChild
  477.          */
  478.         public boolean isAccessibleChildSelected(int i) {
  479.             return (i == getSelectionModel().getSelectedIndex());
  480.         }
  481.  
  482.         /**
  483.          * Selects the nth menu in the menu bar, forcing it to
  484.      * pop up.  If another menu is popped up, this will force
  485.      * it to close.  If the nth menu is already selected, this 
  486.      * method has no effect.
  487.          *
  488.          * @param i the zero-based index of selectable items
  489.          * @see #getAccessibleStateSet
  490.          */
  491.         public void addAccessibleSelection(int i) {
  492.         // first close up any open menu
  493.             int j = getSelectionModel().getSelectedIndex();
  494.         if (i == j) {
  495.         return;
  496.         }
  497.         if (j >= 0 && j < getMenuCount()) {
  498.                 JMenu menu = getMenu(j);
  499.                 if (menu != null) {
  500.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  501. //            menu.setPopupMenuVisible(false);
  502.                 }
  503.         }
  504.         // now popup the new menu
  505.             getSelectionModel().setSelectedIndex(i);
  506.         JMenu menu = getMenu(i);
  507.         if (menu != null) {
  508.         MenuElement me[] = new MenuElement[3];
  509.         me[0] = JMenuBar.this;
  510.         me[1] = menu;
  511.         me[2] = menu.getPopupMenu();
  512.         MenuSelectionManager.defaultManager().setSelectedPath(me);
  513. //        menu.setPopupMenuVisible(true);
  514.         }
  515.         }
  516.     
  517.         /**
  518.          * Removes the nth selected item in the object from the object's
  519.          * selection.  If the nth item isn't currently selected, this
  520.          * method has no effect.  Otherwise, it closes the popup menu.
  521.          *
  522.          * @param i the zero-based index of selectable items
  523.          */
  524.         public void removeAccessibleSelection(int i) {
  525.         if (i >= 0 && i < getMenuCount()) {
  526.         JMenu menu = getMenu(i);
  527.         if (menu != null) {
  528.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  529. //            menu.setPopupMenuVisible(false);
  530.         }
  531.         getSelectionModel().setSelectedIndex(-1);
  532.         }
  533.         }
  534.     
  535.         /**
  536.          * Clears the selection in the object, so that nothing in the
  537.          * object is selected.  This will close any open menu.
  538.          */
  539.         public void clearAccessibleSelection() {
  540.         int i = getSelectionModel().getSelectedIndex();
  541.         if (i >= 0 && i < getMenuCount()) {
  542.         JMenu menu = getMenu(i);
  543.         if (menu != null) {
  544.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  545. //            menu.setPopupMenuVisible(false);
  546.         }
  547.         }
  548.             getSelectionModel().setSelectedIndex(-1);
  549.         }
  550.  
  551.         /**
  552.          * Normally causes every selected item in the object to be selected
  553.          * if the object supports multiple selections.  This method
  554.      * makes no sense in a menu bar, and so does nothing.
  555.          */
  556.         public void selectAllAccessibleSelection() {
  557.         } 
  558.     } // internal class AccessibleJMenuBar
  559.  
  560.  
  561.     /**
  562.      * Returns true to indicate that this component manages focus
  563.      * events internally.
  564.      *
  565.      * @return true
  566.      */
  567.     public boolean isManagingFocus() {
  568.         return true;
  569.     }
  570.  
  571.     KeyboardBinding bindingForKeyStroke(KeyStroke ks,int condition) {
  572.         // Does it exist for the MenuBar?
  573.         KeyboardBinding kbb =  super.bindingForKeyStroke(ks, condition);
  574.         if (kbb != null)
  575.             return kbb;
  576.  
  577.         int i;
  578.         Component subComponents[];
  579.  
  580.         subComponents = getComponents();
  581.         for(i=0 ; i < subComponents.length ; i++) {
  582.             // If 
  583.             if(subComponents[i] instanceof JMenu) {
  584.                 kbb = bindingForKeyStrokeRecursive(subComponents[i], ks, condition);
  585.             }
  586.             if (kbb != null)
  587.                 return kbb;
  588.         }       
  589.         return null;
  590.     }
  591.  
  592.     static KeyboardBinding bindingForKeyStrokeRecursive(Component c,
  593.                                                         KeyStroke ks,int condition) {
  594.         KeyboardBinding kbb = null;
  595.  
  596.         if (c==null)
  597.             return null;
  598.  
  599.         if (c instanceof JComponent) {
  600.             kbb = ((JComponent)c).bindingForKeyStroke(ks, condition);       
  601.             if (kbb != null)
  602.                 return kbb;
  603.         }
  604.  
  605.         if (c instanceof JMenu) {
  606.             JMenu m = (JMenu)c;
  607.             int i;
  608.             Component subComponents[];
  609.             
  610.             subComponents = m.getMenuComponents();
  611.         if (subComponents != null) {
  612.         for(i=0 ; i < subComponents.length ; i++) {
  613.             if(subComponents[i] instanceof JMenuItem) {
  614.             kbb = bindingForKeyStrokeRecursive(subComponents[i], 
  615.                                ks, condition);
  616.             }               
  617.             if (kbb != null)
  618.             return kbb;
  619.         }
  620.         }
  621.         }
  622.         return kbb;
  623.     }
  624.  
  625.  
  626.     private void writeObject(ObjectOutputStream s) throws IOException {
  627.         s.defaultWriteObject();
  628.  
  629.         Object[] kvData = new Object[4];
  630.         int n = 0;
  631.  
  632.         if (selectionModel instanceof Serializable) {
  633.             kvData[n++] = "selectionModel";
  634.             kvData[n++] = selectionModel;
  635.         }
  636.  
  637.         s.writeObject(kvData);
  638.     }
  639.  
  640.  
  641.     private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException 
  642.     {
  643.         s.defaultReadObject();
  644.         Object[] kvData = (Object[])(s.readObject());
  645.  
  646.         for(int i = 0; i < kvData.length; i += 2) {
  647.             if (kvData[i] == null) {
  648.                 break;
  649.             }
  650.             else if (kvData[i].equals("selectionModel")) {
  651.                 selectionModel = (SingleSelectionModel)kvData[i + 1];
  652.             }
  653.         }
  654.     }
  655. }
  656.  
  657.